import sys
import os

from mod_devices import labdevices
from mod_menu import menu
from mod_snmp import snmpwrapper
from mod_colors.terminal_colors import TermColor
from mod_telnet import telnet_client


ciscoSnmpLineType = {
    'UNKNOWN':'1',
    'CONSOLE':'2',
    'TERMINAL':'3',
    'LINEPRINTER':'4',
    'VTY':'5',
    'AUX':'6',
}

class CiscoLab:
    """
    Lab Class
    """
    def __init__(self,comservers,devices):
        # Should the menu loop again ?
        self.__alive = True
        self.__snmpagent = snmpwrapper.SnmpAgent()
        self.__oid = snmpwrapper.cisco_oid

        # Comservers dictionnary
        self.comservers = {}
        for csrv in comservers.keys():
            com = comservers[csrv]
            self.comservers[csrv] = labdevices.ComServer(csrv, com[0], com[1], com[2], com[3], com[4], com[5])

        # Devices dictionnary
        self.devices = {}
        # Device by comserver and line number
        self.index = {}

        for device in devices:
            dev = devices[device]
            self.devices[device] = labdevices.LabDevice(device, self.comservers[dev[0]], dev[1])
            self.index[(self.devices[device].csrv,self.devices[device].tty)] = self.devices[device]


        # Main menu content definition
        self.menu_config = [
            #["title",TermColor.BOLD + "CiscoLab Management Script v2.0" + TermColor.RESET],
            ["title",TermColor.BOLD + "CiscoLab Management Script v2.0" + TermColor.RESET],
            ["option","List devices",self.list_devices,"1"],
            ["option","Free device console",self.free_device,"2"],
            ["option","Open session on device",self.open_session,"3"],
            ["space"],
            ["option","List ComServers",self.list_comservers,"7"],
            ["space"],
            ["option","Logout",self.logout,"9"],
        ]

        # Create display objects
        self.menu = menu.TextMenu()
        self.devices_list = menu.TextMenu()
        self.comservers_list = menu.TextMenu()

        # Define display objects options
        self.menu.options["PADDING_X"] = self.devices_list.options["PADDING_X"] = self.comservers_list.options["PADDING_X"] = 4
        self.menu.options["PADDING_Y"] = self.devices_list.options["PADDING_Y"] = self.comservers_list.options["PADDING_Y"] = 1
        self.menu.options["CLEAR_SCREEN"] = self.devices_list.options["CLEAR_SCREEN"] = self.comservers_list.options["CLEAR_SCREEN"] = True
        self.menu.options["BORDER"] = self.devices_list.options["BORDER"] = self.comservers_list.options["BORDER"] = True

        # Build main menu
        self.menu.build(self.menu_config)

    def start(self):
        """
        Display the menu and start looping
        """
        while self.__alive:
            self.menu.display()
            choice = raw_input("Your choice: ")
            if choice in self.menu.commands.keys():
                self.menu.commands[choice]()

    def get_device_object(self,comserver,line):
        """
        Returns the device object for the given comserver(object) and line(int)
        """
        for device in self.devices:
            if self.devices[device].csrv == comserver and self.devices[device].tty == line:
                print 'found:',self.devices[device].name
                return self.devices[device]

    def list_comservers(self):
        """
        Displays the list of all available comservers
        """
        csrv_list = []
        csrv_list.append('{:12}    {:15}   {:>5}'.format('DEVICE','IP ADDRESS','PORT'))
        csrv_list.append(' ')
        for csrv in sorted(self.comservers.keys()):
            csrv_list.append('{:12}    {:15} : {:5d}'.format(self.comservers[csrv].name,self.comservers[csrv].ipaddress,self.comservers[csrv].port))
        self.comservers_list.reset()
        self.comservers_list.title = TermColor.BOLD + 'ComServers List' + TermColor.RESET
        for line in csrv_list:
            self.comservers_list.add_textLine(line)
        self.comservers_list.display()
        self.wait()

    def list_devices(self):
        """
        Displays the list of all devices including their status
        """
        self.update()
        deviceStatus = [TermColor.RED+'BUSY'+TermColor.RESET,TermColor.GREEN+'FREE'+TermColor.RESET]
        dev_list = []
        dev_list.append('{:12}{:12}{:>5}{:^10}'.format('DEVICE','COMSERVER','TTY','STATUS'))
        dev_list.append(' ')
        for dev in sorted(self.devices.keys()):
            dev_list.append('{:<12}{:<12}{:>5d}{:^19}'.format(self.devices[dev].name,self.devices[dev].csrv.name,self.devices[dev].tty,deviceStatus[self.devices[dev].status],statuswidth=(len(deviceStatus[self.devices[dev].status]))))
        self.devices_list.reset()
        self.devices_list.set_title(TermColor.BOLD + 'Devices status' + TermColor.RESET)
        for line in dev_list:
            self.devices_list.add_textLine(line)
        self.devices_list.display()
        self.wait()

    def wait(self):
        raw_input("\n<Press any key to continue>")

    def update(self):
        """
        Update devices status
        """
        for csrv in self.comservers.keys():
            ttylines = []
            for req,format,linetype in self.__snmpagent.walk('2c',self.comservers[csrv].ipaddress,self.comservers[csrv].roCommunity,self.__oid["TsLineType"]):
                if linetype == ciscoSnmpLineType['TERMINAL']:
                    ttylines.append(req.split('.')[-1])
            for req,format,status in self.__snmpagent.walk('2c',self.comservers[csrv].ipaddress,self.comservers[csrv].roCommunity,self.__oid["TsLineStatus"]):
                line = req.split('.')[-1]
                if line in ttylines:
                    if (self.comservers[csrv],int(line)) in self.index.keys():
                        self.index[(self.comservers[csrv],int(line))].status = not int(status)


    def free_device(self):
        """
        Free device console
        """
        device = raw_input("Which device console would you like to clear ? ")
        if device in self.devices.keys():
            print 'Clearing {} console...'.format(device)
            if self.__snmpagent.set('2c',self.devices[device].csrv.ipaddress,self.devices[device].csrv.rwCommunity,
                                    snmpwrapper.cisco_oid["TsLineClear"],'i',self.devices[device].tty):
                print '{} console cleared'.format(device)
                self.wait()
            else:
                print 'Something went wrong... please try again!'
                self.wait()
        else:
            print 'There is no device named \'{}\'!'.format(device)
            self.wait()

    def open_session(self):
        """
        Open telnet session to the remote console
        Using CTRL+SHIFT+6 closes the telnet sockets and sends the user back to the main menu
        """
        device = raw_input("Which device do you want to use ? ")
        if device in self.devices.keys():
            os.system('clear')
            telnetSession = telnet_client.TelnetClient(self.devices[device].csrv.ipaddress,2000+self.devices[device].tty)
            telnetSession.write('\r\r')
            sys.stdout.write("\nNOTE: Use \"CTRL+Q\" to close session\n")
            sys.stdout.write("\nPress <ENTER> to start...\n")
            telnetSession.client()
        else:
            print 'There is no device named \'{}\'!'.format(device)
            self.wait()


    def logout(self):
        """
        Terminate script and close user connection
        """
        self.__alive = False